#ifndef __C_NGISMODEL_MODEL_CLASS_H__
#define __C_NGISMODEL_MODEL_CLASS_H__

#include "IModelClass.h"
#include "ModelAttribute.h"
#include "ModelBehavior.h"
#include "ModelRuntime.h"
#include <string>
#include "../tinyxml2.h"
using namespace tinyxml2;

namespace NGIS
{
	namespace Model
	{
		class CModelClass : public IModelClass
		{
		public:
			CModelClass()
			{
				mName = "Model Name";
				mUID = "";
				mExecutionStyle = EES_SIMPLE_CALCULATION;

				mModelAttribute = new CModelAttribute();
				mModelBehavior = new CModelBehavior();
				mModelRuntime = new CModelRuntime();
			}

			~CModelClass()
			{
				if (mModelAttribute) mModelAttribute->release();
				if (mModelBehavior) mModelBehavior->release();
				if (mModelRuntime) mModelRuntime->release();
			}

		public:
			virtual void setName(std::string pName) { mName = pName; }

			virtual std::string getName() { return mName; }

			virtual void setUID(std::string pUID) { mUID = pUID; }

			virtual std::string getUID() { return mUID; }

			virtual void setExecutionStyle(EExecutionStyle pStyle) { mExecutionStyle = pStyle; }

			virtual EExecutionStyle getExecutionStyle() { return mExecutionStyle; }

			virtual IModelAttribute* getModelAttribute() { return mModelAttribute; }

			virtual IModelBehavior* getModelBehavior() { return mModelBehavior; }

			virtual IModelRuntime* getModelRuntime() { return mModelRuntime; }

			virtual bool LoadFromXmlFile(const char* fileName) 
			{
				XMLDocument doc;
				doc.LoadFile(fileName);
				const XMLElement* modelClassEle = doc.RootElement();
				mName = modelClassEle->Attribute("name");
				mUID = modelClassEle->Attribute("uid");
				std::string styleStr = "";
				if (modelClassEle->FindAttribute("style")!=NULL)
					styleStr = modelClassEle->Attribute("style");
				else if (modelClassEle->FindAttribute("type")!=NULL)
					styleStr = modelClassEle->Attribute("type");

				if (styleStr == "SimpleCalculation")
				{
					mExecutionStyle = EES_SIMPLE_CALCULATION;
				}
				else if (styleStr == "TimeSeries")
				{
					mExecutionStyle = EES_TIME_SERIES;
				}
				else
				{
					mExecutionStyle = EES_STATE_SIMULATION;
				}

				mModelAttribute->loadFromXml(modelClassEle);
				mModelBehavior->loadFromXml(modelClassEle);
				mModelRuntime->loadFromXml(modelClassEle);

				return true; 
			}

			virtual bool FormatToXmlFile(const char* fileName) 
			{
				XMLDocument doc;
				XMLElement* modelClassEle = doc.NewElement("ModelClass");
				modelClassEle->SetAttribute("name", mName.c_str());
				modelClassEle->SetAttribute("uid", mUID.c_str());
				if (mExecutionStyle == EES_SIMPLE_CALCULATION)
					modelClassEle->SetAttribute("style", "SimpleCalculation");
				else if (mExecutionStyle == EES_TIME_SERIES)
					modelClassEle->SetAttribute("style", "TimeSeries");
				else
					modelClassEle->SetAttribute("style", "StateSimulation");

				doc.LinkEndChild(modelClassEle);
				mModelAttribute->formatToXml(modelClassEle);
				mModelBehavior->formatToXml(modelClassEle);
				mModelRuntime->formatToXml(modelClassEle);

				doc.SaveFile(fileName);

				return true;
			}

			virtual bool LoadFromXmlStream(const char* xmlStr) 
			{
				XMLDocument doc;
				doc.Parse(xmlStr);
				XMLElement* modelClassEle = doc.RootElement();
				mName = modelClassEle->Attribute("name");
				mUID = modelClassEle->Attribute("uid");
				std::string styleStr = modelClassEle->Attribute("style");
				if (styleStr == "SimpleCalculation")
				{
					mExecutionStyle = EES_SIMPLE_CALCULATION;
				}
				else if (styleStr == "TimeSeries")
				{
					mExecutionStyle = EES_TIME_SERIES;
				}
				else
				{
					mExecutionStyle = EES_STATE_SIMULATION;
				}

				mModelAttribute->loadFromXml(modelClassEle);
				mModelBehavior->loadFromXml(modelClassEle);
				mModelRuntime->loadFromXml(modelClassEle);

				return true; 
			}

			virtual bool FormatToXmlStream(std::string& xmlStr) 
			{ 
				XMLDocument doc;
				XMLElement* modelClassEle = doc.NewElement("ModelClass");
				modelClassEle->SetAttribute("name", mName.c_str());
				modelClassEle->SetAttribute("uid", mUID.c_str());
				if (mExecutionStyle == EES_SIMPLE_CALCULATION)
					modelClassEle->SetAttribute("style", "SimpleCalculation");
				else if (mExecutionStyle == EES_TIME_SERIES)
					modelClassEle->SetAttribute("style", "TimeSeries");
				else
					modelClassEle->SetAttribute("style", "StateSimulation");

				doc.LinkEndChild(modelClassEle);
				mModelAttribute->formatToXml(modelClassEle);
				mModelBehavior->formatToXml(modelClassEle);
				mModelRuntime->formatToXml(modelClassEle);

				tinyxml2::XMLPrinter printer;
				doc.Print(&printer);
				xmlStr = printer.CStr();

				return true;
			}

			virtual bool compareOther(IModelClass* pClass, bool withRuntime, std::string& obj, std::string& name)
			{
				bool flag = false;
				if (mModelAttribute) 
				{
					flag = mModelAttribute->compareOther(pClass->getModelAttribute(), obj, name);
					if (flag == false)
						return false;
				}
				if (mModelBehavior)
				{
					flag = mModelBehavior->compareOther(pClass->getModelBehavior(), obj, name);
					if (flag == false)
						return false;
				}
				if (withRuntime && mModelRuntime)
				{
					flag = mModelRuntime->compareOther(pClass->getModelRuntime(), obj, name);
					if (flag == false)
						return false;
				}
				return true;
			}
		private:
			std::string mName;
			std::string mUID;
			EExecutionStyle mExecutionStyle;

			CModelAttribute* mModelAttribute;
			CModelBehavior* mModelBehavior;
			CModelRuntime* mModelRuntime;

		};
	}
}

#endif

